<template>
  <n-space :wrap="false">
    <n-date-picker v-bind="props" :is-date-disabled="disablePreviousDate" :default-time="['00:00:00', '23:59:59']" />
    <n-radio-group
      v-model:value="radioValue"
      :size="props.size"
      @update:value="handlePickerOptions"
      @click="handleClickRadio"
    >
      <n-radio-button v-for="(item, index) in shortcutsOption" :key="index" :value="item.value">
        {{ item.label }}
      </n-radio-button>
    </n-radio-group>
  </n-space>
</template>

<script lang="ts">
  import { computed, defineComponent, reactive, toRefs, watch } from 'vue'
  import { NSpace, NDatePicker, NRadioGroup, NRadioButton, useMessage } from 'naive-ui'
  import { useStore } from '@/store'
  import { useDictionary } from '@/hooks'
  import { formatDate } from '@/utils'
  import { startOfDay } from 'date-fns'

  const currentDate = new Date(),
    y = currentDate.getFullYear(),
    m = currentDate.getMonth(),
    w = currentDate.getDay()
  export default defineComponent({
    name: 'XDatePickerActions',
    components: {
      NSpace,
      NDatePicker,
      NRadioGroup,
      NRadioButton
    },
    props: {
      ...NDatePicker.props,
      clearable: {
        type: Boolean,
        default: true
      },
      closeOnSelect: {
        type: Boolean,
        default: true
      },
      placeholder: {
        type: String,
        default: '请选择日期范围'
      },
      type: {
        type: String,
        default: 'datetimerange'
      },
      // 选中一个日期后，前后可选最大天数
      maxDay: {
        type: Number,
        default: 90
      },
      // 可以快捷选择的字典数据
      dict: {
        type: String,
        default: 'DATE_SHORTCUTS_LIST'
      },
      shortcuts: {
        type: Object,
        default: () => ({
          上月: () => {
            const monthFirstDay = new Date(y, m - 1, 1)
            const monthLastDay = new Date(y, m, 0)
            return [+monthFirstDay, +monthLastDay]
          },
          本月: () => {
            const monthFirstDay = new Date(y, m, 1)
            return [+monthFirstDay, +currentDate]
          }
        })
      },
      // 最小可选日期
      minDate: {
        type: [Date, Number, String],
        default: 0
      },
      showRecent: {
        type: Boolean,
        default: true
      },
      showWeeks: {
        type: Boolean,
        default: false
      },
      showMonths: {
        type: Boolean,
        default: false
      },
      show15Days: {
        type: Boolean,
        default: false
      }
    },
    emits: ['update:value'],
    setup($props, { emit: $emit }) {
      const $dictionary = useDictionary()
      $dictionary.get($props.dict)
      const $message = useMessage()
      const $store = useStore()
      const $state: any = reactive({
        isClickRadio: false, // 判断是否主动点击时间radio，用于时间改变时如何选中radio
        radioValue: null,
        props: toRefs($props) || {},
        // 字典
        dictionary: computed(() => $store.getters.dictionary),
        shortcutsOption: computed(() => {
          let list = $state.dictionary['DATE_SHORTCUTS_LIST']?.slice(0, 2) || []
          if ($props.showRecent) {
            list = $state.dictionary['DATE_SHORTCUTS_LIST']?.filter((item) => item.value <= $props.maxDay) || []
          }
          if ($props.showWeeks) {
            list.push(
              {
                label: '本周',
                value: 'thisWeek'
              },
              {
                label: '上周',
                value: 'lastWeek'
              }
            )
          }
          if ($props.showMonths) {
            list.push(
              {
                label: '本月',
                value: 'thisMonth'
              },
              {
                label: '上月',
                value: 'lastMonth'
              }
            )
          }
          if (!$props.show15Days) {
            list.forEach((item: any, index: number) => {
              if (item.value === 15) {
                list.splice(index, 1)
              }
            })
          }
          return list
        }),
        disablePreviousDate(ts: number, type: string, range: number[] | null) {
          if (startOfDay(ts).valueOf() > startOfDay(new Date()).valueOf()) {
            return true
          }

          // 最小可选择日期
          if ($props.minDate && startOfDay(ts).valueOf() < startOfDay($props.minDate).valueOf()) {
            return true
          }

          if ($props.maxDay) {
            if (type === 'start' && range !== null) {
              return startOfDay(range[1]).valueOf() - startOfDay(ts).valueOf() > 86400000 * ($props.maxDay - 1)
            }
            if (type === 'end' && range !== null) {
              return startOfDay(ts).valueOf() - startOfDay(range[0]).valueOf() > 86400000 * ($props.maxDay - 1)
            }
          }
          return false
        }
      })

      watch(
        () => $props.value,
        () => {
          updateRadioValue()
        }
      )

      watch(
        () => $state.shortcutsOption,
        () => {
          updateRadioValue()
        }
      )

      const updateRadioValue = () => {
        if ($state.isClickRadio) {
          $state.isClickRadio = false
          return
        }
        const value = $props.value
        if (value && value.length === 2) {
          const start = formatDate(value[0])
          const end = formatDate(value[1])
          const now = formatDate(new Date())

          let count: string | number | null = null
          // 结束时间为今天的，那么才需要校验当前的日期范围是否在字典选项内
          if (end === now) {
            const t = +new Date() - value[0]
            let extra = 1
            if (start === now) {
              extra = 0
            }
            count = Math.floor(t / 86400000) + extra
          } else {
            // 校验是否为昨天，并且去匹配字典里是否有昨天
            const time = +new Date() - value[0]
            if (start === end && Math.floor(time / 86400000) === 1) {
              count = 1
            } else {
              count = Math.floor(time / 86400000)
            }
          }
          const find = $state.shortcutsOption.find((item: { value: string }) => item.value === count)

          if (find) {
            $state.radioValue = find.value
          } else {
            $state.radioValue = null
          }
        } else {
          $state.radioValue = null
        }
      }
      updateRadioValue()

      const handlePickerOptions = (val: number | string) => {
        const now = new Date()
        const start = new Date()

        switch (val) {
          case 'thisWeek':
            // 获取本周的第一天
            const firstDayOfWeek = new Date(currentDate)
            firstDayOfWeek.setDate(currentDate.getDate() - currentDate.getDay() + 1)
            const firstDayOfWeekStr = firstDayOfWeek.toISOString().split('T')[0]
            $emit('update:value', [+new Date(firstDayOfWeekStr).setHours(0, 0, 0), +new Date().setHours(23, 59, 59)])
            break
          case 'lastWeek':
            // 获取上周的第一天
            const firstDayOfLastWeek = new Date(currentDate)
            firstDayOfLastWeek.setDate(currentDate.getDate() - currentDate.getDay() - 6)

            // 获取上周的最后一天
            const lastDayOfLastWeek = new Date(currentDate)
            lastDayOfLastWeek.setDate(currentDate.getDate() - currentDate.getDay())

            // 将日期转换为字符串格式（可根据需要进行格式化）
            const firstDayOfLastWeekStr = firstDayOfLastWeek.toISOString().split('T')[0]
            const lastDayOfLastWeekStr = lastDayOfLastWeek.toISOString().split('T')[0]

            $emit('update:value', [
              +new Date(firstDayOfLastWeekStr).setHours(0, 0, 0),
              +new Date(lastDayOfLastWeekStr).setHours(23, 59, 59)
            ])
            break
          case 'thisMonth':
            $emit('update:value', [+new Date(y, m, 1).setHours(0, 0, 0), +new Date().setHours(23, 59, 59)])
            break
          case 'lastMonth':
            $emit('update:value', [+new Date(y, m - 1, 1).setHours(0, 0, 0), +new Date(y, m, 0).setHours(23, 59, 59)])
            break
          case 0:
          case 1:
            start.setDate(start.getDate() - val)
            $emit('update:value', [+new Date(start).setHours(0, 0, 0), +new Date(start).setHours(23, 59, 59)])
            break
          case 7:
          case 15:
          case 30:
          case 60:
          case 90:
            start.setDate(start.getDate() - val + 1)
            // 最小可选择日期
            if ($props.minDate && startOfDay(start).valueOf() < startOfDay($props.minDate).valueOf()) {
              $message.warning('超出可选最小日期，请重新选择')
            } else {
              // 等于1时，表示查看昨天的数据，那么开始结束时间都用昨天的日期
              $emit('update:value', [+new Date(start).setHours(0, 0, 0), +new Date(now).setHours(23, 59, 59)]) // 近7天等不包含今天 所以减去86400000
            }
            break
          default:
            break
        }
      }

      function handleClickRadio() {
        $state.isClickRadio = true
      }

      return {
        ...toRefs($state),
        handlePickerOptions,
        handleClickRadio
      }
    }
  })
</script>

<style></style>
